<?php

namespace App\Jobs\Stats;

use Illuminate\Support\Str;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Admin\StatsTask\StatsTask;
use App\Core\Traits\Numeral;

abstract class Stats implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Numeral;

    /**
     * 获取统计实例
     *
     * @return static|mixed
     */
    protected function instance()
    {
        if (!!config('elasticsearch.default')) {
            // 基础类名
            $name = class_basename(static::class);
            // 类名解析
            $class = Str::replaceLast($name, "Elasticsearch\\{$name}", static::class);
            // 存在则创建
            if (class_exists($class)) {
                return new $class($this->task);
            }
        }
        return $this;
    }

    /**
     * 执行统计任务。
     *
     * @return void
     */
    abstract public function stats();

    /**
     * 任务可以尝试的最大次数。
     *
     * @var int
     */
    public $tries = 3;

    /**
     * 在超时之前任务可以运行的秒数。
     *
     * @var int
     */
    public $timeout = 120;

    /**
     * 如果任务的模型不再存在，则删除该任务
     *
     * @var bool
     */
    public $deleteWhenMissingModels = true;

    /**
     * 任务
     *
     * @var StatsTask
     */
    protected $task;

    /**
     * 创建一个新的任务实例。
     *
     * @param StatsTask|null $task
     */
    public function __construct(?StatsTask $task = null)
    {
        $this->task = $task;
    }

    /**
     * 执行任务。
     *
     * @return void
     */
    public function handle()
    {
        if (!$this->task || $this->task->status != StatsTask::STATUS_JOB) {
            return null;
        }

        // 开始执行任务
        $this->start();

        // 执行统计任务
        $this->instance()->stats();

        // 任务执行成功
        $this->succeeded();
    }

    /**
     * 开始执行任务。
     */
    public function start()
    {
        $this->task->attempts += 1;
        $this->task->status = StatsTask::STATUS_START;
        $this->task->save();
    }

    /**
     * 任务执行成功。
     */
    public function succeeded()
    {
        $this->task->status = StatsTask::STATUS_SUCCEE;
        $this->task->save();
    }

    /**
     * 任务执行失败。
     *
     * @param \Throwable $exception
     * @return void
     */
    public function failed(\Throwable $exception)
    {
        $this->task->status = StatsTask::STATUS_ERROR;
        $this->task->save();
    }
}
